// <editor-fold defaultstate="collapsed" desc="GNU GPLv3 Header">
/*
 * File:   LCD_TM162JCAWG1.c
 *
 * Copyright (C) 2013 Robert Antoni Buj Gelonch <rbuj@uoc.edu>
 * Copyright (C) 2013 David Megias Jimenez <dmegias@uoc.edu>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
// </editor-fold>

// <editor-fold defaultstate="collapsed" desc="includes">
#include "../include/LCD_TM162JCAWG1.h"
// </editor-fold>

// <editor-fold defaultstate="collapsed" desc="pinout info">
/*
 * LCD_RS   : RB15
 * LCD_E    : RD4
 * LCD_RW   : RD5
 * LCD_DATA : RE[0:7]
 * 40 MIPS  : 25 ns / 1 MCU cycle
 */
// </editor-fold>

// <editor-fold defaultstate="collapsed" desc="lcd_init">

/* Init a TM162JCAWG1 LCD Display
 * Execution cycles (aprox) : 1.270.484 cycles
 * (rcalls + returns : +5+5+4x10 cycles)
 * Execution Time (aprox)   :    31,8 ms
 */
void lcd_init(void) {
    /*
     * Wait more than 30ms after Vdd on
     * 80.000 cycles
     */
    __delay_ms(30UL);

    /*
     * set the initial state
     * 4 cycles
     */
    LCD_DATA &= 0xFF00;
    LCD_RW = 0;
    LCD_RS = 0;
    LCD_E = 0;

    /*
     * set the pin direction
     * 4 cycles
     */
    LCD_DATA_TRIS &= 0xFF00;
    LCD_RW_TRIS = 0; // output pin
    LCD_RS_TRIS = 0; // output pin
    LCD_E_TRIS = 0; // output pin

    /**********************************************************
     * 1st LCD initialization sequence: Function Set
     *  1.621 cycles
     **********************************************************/
    lcd_function_set_8bit();

    /**********************************************************
     * 2nd LCD initialization sequence: Display ON/OFF Control
     *  1.621 cycles
     ********************************************++************/
    lcd_D_on_C_off_B_off();

    /**********************************************************
     * 3rd LCD initialization sequence: Clear Display
     * 65.621 cycles
     *********************************************************/
    lcd_home_clr();

    /**********************************************************
     * 4th LCD initialization sequence: Entry mode set
     *  1.621 cycles
     *********************************************************/
    lcd_ems_inc_shift_off();
}
// </editor-fold>

// <editor-fold defaultstate="collapsed" desc="lcd_cmd">

/* subroutiune for lcd commands
 * Execution cycles (aprox) : 1.621 cycles (rcall + return : +10 cycles)
 * Execution Time (aprox)   :  0,04 ms
 * byval cmd
 */
void lcd_cmd_short_delay(char cmd) {
    LCD_DATA &= 0xFF00; // prepare RD0 - RD7
    LCD_DATA |= cmd; // command byte to lcd
    /*
     * RS and CSB setup
     * min : 60 ns
     */
    LCD_RW = 0;
    LCD_RS = 0;
    /* RS, R/W Setup Time more than 60 ns: start */
    Nop();
    Nop();
    Nop();
    /* RS, R/W Setup Time more than 60 ns: end */
    /*
     * E pulse width high
     * min : 250 ns
     */
    LCD_E = 1;
    /* Enable H pulse more than 300ns: start */
    Nop(); // 1
    Nop(); // 2
    Nop(); // 3
    Nop(); // 4
    Nop(); // 5
    Nop(); // 6
    Nop(); // 7
    Nop(); // 8
    Nop(); // 9
    Nop(); // 10
    Nop(); // 11
    Nop(); // 12
    /* Enable H pulse more than 300ns: end */
    /*
     * E pulse width low
     * min : 200 ns
     */
    LCD_E = 0;
    __delay_us(40UL);
}

/* subroutiune for lcd commands
 * Execution cycles (aprox) : 65.621 cycles (rcall + return : +10 cycles)
 * Execution Time (aprox)   :    1,6 ms
 * byval cmd
 */
void lcd_cmd_long_delay(char cmd) {
    LCD_DATA &= 0xFF00; // prepare RD0 - RD7
    LCD_DATA |= cmd; // command byte to lcd
    /*
     * RS and CSB setup
     * min : 60 ns
     */
    LCD_RW = 0;
    LCD_RS = 0;
    /* RS, R/W Setup Time more than 60 ns: start */
    Nop();
    Nop();
    Nop();
    /* RS, R/W Setup Time more than 60 ns: end */
    /*
     * E pulse width high
     * min : 250 ns
     */
    LCD_E = 1;
    /* Enable H pulse more than 300ns: start */
    Nop(); // 1
    Nop(); // 2
    Nop(); // 3
    Nop(); // 4
    Nop(); // 5
    Nop(); // 6
    Nop(); // 7
    Nop(); // 8
    Nop(); // 9
    Nop(); // 10
    Nop(); // 11
    Nop(); // 12
    /* Enable H pulse more than 300ns: end */
    /*
     * E pulse width low
     * min : 200 ns
     */
    LCD_E = 0;
    __delay_us(1640UL);
}

// </editor-fold>

// <editor-fold defaultstate="collapsed" desc="lcd_data">

/* subroutine for lcd data
 * Execution cycles (aprox) : 1.620 cycles (rcall + return : +10 cycles)
 * Execution Time (aprox)   :  0,04 ms
 * byval data
 */
void lcd_data(char data) {
    /*
     * RS and CSB setup
     * min : 60 ns
     */
    LCD_RW = 0;
    LCD_RS = 1;
    /* RS, R/W Setup Time more than 60 ns: start */
    Nop();
    /*
     * E pulse width high
     * min : 250 ns
     */
    LCD_DATA &= 0xFF00;
    LCD_DATA |= data;
    /* RS, R/W Setup Time more than 60 ns: end */
    LCD_E = 1;
    /* Enable H pulse more than 300ns: start */
    Nop(); // 1
    Nop(); // 2
    Nop(); // 3
    Nop(); // 4
    Nop(); // 5
    Nop(); // 6
    Nop(); // 7
    Nop(); // 8
    Nop(); // 9
    Nop(); // 10
    Nop(); // 11
    Nop(); // 12
    /* Enable H pulse more than 300ns: end */
    /*
     * E pulse width low
     * min : 200 ns
     */
    LCD_E = 0;
    LCD_RS = 0; // change to instruction mode (default)
    __delay_us(40UL);
}

/* subroutine for writting a string in the LCD
 * byref data
 * byval count
 */
void lcd_puts(unsigned char *data, unsigned char count) {
    while (count) {
        lcd_data(*data++);
        count--;
    }
}

// </editor-fold>

// <editor-fold defaultstate="collapsed" desc="lcd_set_address">

/* subroutine for setting the CDRAM address
 * byval address
 */
void lcd_set_address_CGRAM(unsigned char address) {
    unsigned char temp;
    temp = (address & 0x0F) | 0x40;
    lcd_cmd_short_delay(temp);
}

/* subroutine for setting the DDRAM address
 * byval address
 */
void lcd_set_address_DDRAM(unsigned char address) {
    unsigned char temp;
    temp = (address & 0xEF) | 0x80;
    lcd_cmd_short_delay(temp);
}

// </editor-fold>
